#ifndef FILESTORAGE_HPP_
#define FILESTORAGE_HPP_

#include "datastorage.hpp"
#include <string>
#include "mmapadapter.hpp"
#include <unordered_map>
#include <atomic>
#include <map>
#include <vector>

#define LOGGING_INFO
#include "logger.h"

using std::string;
using std::atomic;
using std::multimap;
using std::unordered_map;
using std::vector;
using std::map;
using std::pair;
using std::make_pair;

struct Block { // FIXME: Move Block and BlockAddr declaration into FileStorage class
	char* data;
	int locked;
};

struct BlockAddr {
	size_t block;
	size_t pos;
	size_t size;
	inline bool operator==(const BlockAddr& a) {
		return this->block == a.block && this->pos == a.pos;
	} 
};

class FileStorage : public DataStorage {

	public:
	FileStorage(size_t size, const string& path);
	virtual ~FileStorage();
	virtual DataChunk* alloc(size_t);
	
	private:
	virtual void free(DataChunk*);
	virtual char* get(DataChunk*);
	virtual void release(DataChunk*);
	
	inline pair<DataChunk* const, BlockAddr>* getChunkPair(DataChunk* chunk)
	{
		auto chunk_pair = chunks_.find(chunk);
		if (chunk_pair == chunks_.end()) {
			LOG_ERROR("no such chunk");
			throw MemAllocException(MemAllocException::E_INVAL);
		}
		return &(*chunk_pair);
		/*
		pair<DataChunk*, BlockAddr>* chunk_pair = nullptr;
		for (auto& pair : chunks_)
		if(pair.first == chunk) {
			chunk_pair = &pair;
			break;
		}
		if (!chunk_pair) {
			LOG_ERROR("no such chunk");
			throw MemAllocException(MemAllocException::E_INVAL);
		}
		return chunk_pair;
		* */
	}
	
	inline void removeChunkPair(DataChunk* chunk)
	{
		// FIXME: check chunks_.find(chunk) != chunks_.end()
		chunks_.erase(chunks_.find(chunk));
	}
	
	// FIXME: Why should you copy BlockAddr. Use pointers instead
	inline void appendChunkPair(DataChunk* chunk, BlockAddr block)
	{
		chunks_.insert(make_pair(chunk, block));
	}
	
	size_t block_size_;
	size_t block_num_;
	size_t block_act_;
	
	MappableFile* swap_;
	size_t data_size_;
	size_t data_free_;
	
	multimap<size_t, BlockAddr> holes_; // FYI: size_t дублируется. Есть же multiset
	map<DataChunk*, BlockAddr> chunks_; 
	vector<Block> blocks_;
	
	mutex global_mutex_; // FIXME: Why don't you use it in your FileStorage?.
};

#endif // FILESTORAGE_HPP_
